#include "protocol.h"
#include "client.h"

static int Packet(char *sendbuff, enum CMD_NO cmd_no)
{
	int i = 0;
	int pkg_len = 8;
	/* 包头 */
	sendbuff[i++] = 0xC0;
	
	/* pkg_len */
	sendbuff[i++] = pkg_len & 0xff;
	sendbuff[i++] = pkg_len >> 8 & 0xff;
	sendbuff[i++] = pkg_len >> 16 & 0xff;
	sendbuff[i++] = pkg_len >> 24 & 0xff;

	/* cmd_len */
	sendbuff[i++] = cmd_no & 0xff;
	sendbuff[i++] = cmd_no >> 8 & 0xff;
	sendbuff[i++] = cmd_no >> 16 & 0xff;
	sendbuff[i++] = cmd_no >> 24 & 0xff;

	/* 包尾 */
	sendbuff[i++] = 0xC0;
}

static int getPacket(char *optbuff, char *sendbuff)
{
    int i = 0;
    /* 减去get 空格 和\n的长度*/
    int arg_len_1 = strlen(optbuff) - 5;
    int pkg_len = 4 + 4 + 4 + arg_len_1;

    /* 包头 */
    sendbuff[i++] = 0xC0;

    /* pkg_len */
    sendbuff[i++] = pkg_len & 0xff;
    sendbuff[i++] = pkg_len >> 8 & 0xff;
    sendbuff[i++] = pkg_len >> 16 & 0xff;
    sendbuff[i++] = pkg_len >> 24 & 0xff;

    /* cmd_len */
    enum CMD_NO cmd_no = FTP_CMD_GET;
    sendbuff[i++] = cmd_no & 0xff;
    sendbuff[i++] = cmd_no >> 8 & 0xff;
    sendbuff[i++] = cmd_no >> 16 & 0xff;
    sendbuff[i++] = cmd_no >> 24 & 0xff;

    /* arg_len_1 */
    sendbuff[i++] = arg_len_1 & 0xff;
    sendbuff[i++] = arg_len_1 >> 8 & 0xff;
    sendbuff[i++] = arg_len_1 >> 16 & 0xff;
    sendbuff[i++] = arg_len_1 >> 24 & 0xff;

    /* arg_data*/
    char *p = optbuff + 4;

    while (*p != '\n')
    {
        sendbuff[i++] = *p;
        p++;
    }
    /* 包尾 */
    sendbuff[i++] = 0xC0;
}

void handle(char *savefile, int confd)
{
    int fd;
    char realfile[NAMESIZE] = {0};
    sprintf(realfile, "%s/%s", SAVEPATH, savefile);
    fd = open(realfile, O_RDWR | O_CREAT | O_TRUNC, 0666);
    if (fd < 0)
    {
        perror("open()");
        exit(1);
    }
    char revbuff[BUFFSIZE] = {0};

    while (1)
    {
        int ret = recv(confd, revbuff, BUFFSIZE, 0);

        write(fd, revbuff, ret);
        if (ret < BUFFSIZE)
            break;
    }
}

static int unpack(char *recvbuff, int confd)
{
	u_int8_t ch;
	int i = 0;

	u_int8_t outbuff[BUFFSIZE] = {0};
	/* 读取到包头 */
	do
	{
		ch = recvbuff[i++];
	
	}while (ch != 0xC0);
	
	/* 为防止读到错误的包头*/
	while (ch == 0xC0)
	{
		ch = recvbuff[i++];
	}
	int k = 0;

	/* 解析真正内容 @pkg_len:内容长度 @cmd_no:请求命令*/
	while (ch != 0xC0)
	{
		outbuff[k++] = ch;
		ch = recvbuff[i++];
	}

	i = 0;
	int pkg_len = outbuff[i++] | outbuff[i++] << 8 | outbuff[i++] << 16 | outbuff[i++] << 24;
    if (pkg_len != k)
    {
        fprintf(stderr, "faild\n");
        return -1;
    }
    int cmd_no = outbuff[i++] | outbuff[i++] << 8 | outbuff[i++] << 16 | outbuff[i++] << 24;
    int resp_len = outbuff[i++] | outbuff[i++] << 8 | outbuff[i++] << 16 | outbuff[i++] << 24;
    if (outbuff[i++] != 0)
    {
        fprintf(stderr, "faild\n");
        return -1;
    }

    if (cmd_no == FTP_CMD_LS)
    {
        puts(outbuff+i);
    }
    else if (cmd_no == FTP_CMD_GET)
    {
        int filesize = outbuff[i++] | outbuff[i++] << 8 | outbuff[i++] << 16 | outbuff[i++] << 24;
        printf("%d\n", filesize);

        char savefile[BUFFSIZE] = {0};
        int len = 0;
        while (i < k)
        {
            savefile[len++] = outbuff[i];
            i++;
        }
        handle(savefile, confd);
    }
	return 0;
}

int packhandle(char *optbuff, struct FSM_ST *fsm) {
    if (strncmp(optbuff, "ls", 2) == 0)
    {
        fsm->cmd_no = FTP_CMD_LS;
        Packet(fsm->sendbuff, fsm->cmd_no);
    }
    else if (strncmp(optbuff, "get", 3) == 0)
    {
        fsm->cmd_no = FTP_CMD_GET;
        getPacket(optbuff, fsm->sendbuff);
    }
    else if (strncmp(optbuff, "bye", 3) == 0)
    {
        fsm->cmd_no = FTP_CMD_BYE;
       Packet(fsm->sendbuff, fsm->cmd_no);
    }
    else
		return -1;
	return 0;
}


void driver(struct FSM_ST *fsm)
{
    char getbuff[BUFFSIZE] = {0};
    switch (fsm->state)
	{
        case FSM_PACKET:
			fgets(getbuff, BUFFSIZE, stdin);
			if (packhandle(getbuff, fsm) < 0)
			{
				fsm->errstr = "getPacket()";
				fsm->state = FSM_EX;
				break;
			}
			fsm->state = FSM_SEND;
			break;
		case FSM_SEND:
			if (send(fsm->confd, fsm->sendbuff, BUFFSIZE, 0) < 0)
			{
				fsm->errstr = "send()";
				fsm->state = FSM_EX;
				break;
			}
			if (fsm->cmd_no == FTP_CMD_BYE)
			    exit(0);
			fsm->state = FSM_RECV;
			break;
		case FSM_RECV:
			if (recv(fsm->confd, fsm->recvbuff, BUFFSIZE, 0) < 0)
			{
				fsm->errstr = "recv()";
				fsm->state = FSM_EX;
				break;
			}
		    if (unpack(fsm->recvbuff, fsm->confd) < 0)
			{
				fsm->errstr = "unpack()";
				fsm->state = FSM_EX;
				break;
			}
			fsm->state = FSM_HANDLE;
			break;

		case FSM_HANDLE:
			memset(fsm->recvbuff, 0, BUFFSIZE);
            memset(fsm->sendbuff, 0, BUFFSIZE);
            fsm->state = FSM_PACKET;
			break;
		case FSM_CANCEL:
			break;
		case FSM_EX:
		    perror(fsm->errstr);
		    fsm->state = FSM_T;
			break;
		case FSM_T:
		    exit(1);
			break;
		default:
		    abort();
			break;
	}

}

int main(int argc, char **argv)
{
	if (argc < 3)
	{
		fprintf(stderr, "Usage:\n");
		exit(1);
	}
	/* 创建一个套接字 */
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);	
	if (sockfd < 0)
	{
		perror("socket()");
		exit(1);
	}
	
	struct sockaddr_in server;
	server.sin_family = AF_INET;
	server.sin_port = htons(atoi(argv[2]));
	inet_pton(AF_INET, argv[1], &server.sin_addr.s_addr);
	
	/* 连接服务端 */
	if (connect(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
	{
		perror("connect()");
		exit(1);
	}
    struct FSM_ST fsm;
    fsm.state = FSM_PACKET;
    fsm.confd = sockfd;
    fsm.cmd_no = 0;
    memset(fsm.recvbuff, 0, BUFFSIZE);
    memset(fsm.sendbuff, 0, BUFFSIZE);
	while (1)
	{
		driver(&fsm);
	}
	
	exit(0);
}
